/*
 * Copyright 2021 Huawei Technologies Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.edgegallery.thirdsystem.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.edgegallery.thirdsystem.bean.vo.ThirdSystemVo;
import org.edgegallery.thirdsystem.constant.ResponseConst;
import org.edgegallery.thirdsystem.repository.ThirdSystem;
import org.edgegallery.thirdsystem.repository.mapper.ThirdSystemMapper;
import org.edgegallery.thirdsystem.utils.AesUtil;
import org.edgegallery.thirdsystem.utils.exception.AppException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

@Service("ThirdSystemService")
public class ThirdSystemService {
    private static final Logger LOGGER = LoggerFactory.getLogger(ThirdSystemService.class);

    private static final String CREATE_THIRD_SYSTEM_ERR_MESSAGES = "create third system fail.";

    private static final String CREATE_THIRD_SYSTEM_SUCCESS_MESSAGES = "create third system success.";

    private static final String QUERY_THIRD_SYSTEM_ERR_MESSAGES = "get third system fail.";

    private static final String UPDATE_THIRD_SYSTEM_ERR_MESSAGES = "update third system fail.";

    private static final String UPDATE_THIRD_SYSTEM_SUCCESS_MESSAGES = "update third system success.";

    private static final String DELETE_THIRD_SYSTEM_ERR_MESSAGES = "delete third system fail.";

    private static final String DELETE_THIRD_SYSTEM_SUCCESS_MESSAGES = "delete third system success.";

    private static final String THIRD_SYSTEM_ERR_NOT_FOUND_MESSAGES = "third system not exist.";

    @Autowired
    ThirdSystemMapper thirdSystemMapper;

    @Value("${client.client-id:}")
    private String clientId;

    /**
     * create a thirdSystem.
     *
     * @param thirdSystem thirdSystem
     * @return String
     */
    public ResponseEntity<String> createThirdSystem(ThirdSystem thirdSystem) throws IOException {
        thirdSystem.setId(UUID.randomUUID().toString());

        // if config file exist, need transfer content from file
        String configContent = thirdSystem.getConfigContent();
        if (configContent != null && !configContent.isEmpty()) {
            thirdSystem.setConfigContent(decodeFile(thirdSystem.getId(), configContent));
        }

        // if password is not empty, need encrypt
        String password = thirdSystem.getPassword();
        if (password != null && !password.isEmpty()) {
            thirdSystem.setPassword(AesUtil.encode(clientId, password));
        }

        int ret = thirdSystemMapper.insertSelective(thirdSystem);
        if (ret > 0) {
            LOGGER.info(CREATE_THIRD_SYSTEM_SUCCESS_MESSAGES);
            return ResponseEntity.ok(CREATE_THIRD_SYSTEM_SUCCESS_MESSAGES);
        } else {
            throw new AppException(CREATE_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_CREATE_THIRD_SYSTEM_FAILED);
        }
    }

    // base64 decode
    private String decodeFile(String id, String base64) throws IOException {
        try {
            Files.write(Paths.get(id), Base64.getDecoder().decode(base64), StandardOpenOption.CREATE);
        } catch (IOException e) {
            LOGGER.error("Failed to decode, {}", e.getMessage());
        }
        return readFile(new File(id));
    }

    private String readFile(File file) throws IOException {
        StringBuilder sb = new StringBuilder();
        String temp;
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            while ((temp = reader.readLine()) != null) {
                sb.append(temp);
            }
        } catch (FileNotFoundException e) {
            LOGGER.error("File not exist, {}", e.getMessage());
        } catch (IOException e) {
            LOGGER.error("Failed to decode, {}", e.getMessage());
        }
        deleteFile(file);
        return sb.toString();
    }

    private void deleteFile(File file) throws IOException {
        Files.delete(file.toPath());
    }

    /**
     * query a thirdSystem by id.
     *
     * @param id thirdSystem id
     * @return ThirdSystem
     */
    public ResponseEntity<ThirdSystem> getThirdSystemById(String id) {
        ThirdSystem ret = thirdSystemMapper.selectByPrimaryKey(id);
        if (ret != null) {
            // if password is not empty, need encrypt
            String password = ret.getPassword();
            if (password != null && !password.isEmpty()) {
                ret.setPassword(AesUtil.decode(clientId, password));
            }
            return ResponseEntity.ok(ret);
        } else {
            throw new AppException(QUERY_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_QUERY_THIRD_SYSTEM_FAILED);
        }
    }

    /**
     * query a thirdSystem by id.
     *
     * @param id thirdSystem id
     * @return ThirdSystemVo
     */
    public ResponseEntity<ThirdSystemVo> getWebThirdSystemById(String id) {
        ThirdSystem ret = thirdSystemMapper.selectByPrimaryKey(id);
        if (ret != null) {
            return ResponseEntity.ok(ret.toVo());
        } else {
            throw new AppException(QUERY_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_QUERY_THIRD_SYSTEM_FAILED);
        }
    }

    /**
     * count all thirdSystems.
     *
     * @param types types
     * @return count
     */
    public ResponseEntity<JSONArray> countThirdSystem(String[] types) {
        JSONArray result = new JSONArray();
        for (String type : types) {
            int totalNum = thirdSystemMapper.countThirdSystems(type, null);
            int activeNum = thirdSystemMapper.countThirdSystems(type, "active");
            int inactiveNum = totalNum - activeNum;
            JSONObject numObj = new JSONObject();
            numObj.put("totalNum", totalNum);
            numObj.put("activeNum", activeNum);
            numObj.put("inactiveNum", inactiveNum);
            JSONObject typeObj = new JSONObject();
            typeObj.put(type, numObj);
            result.add(typeObj);
        }
        return ResponseEntity.ok(result);
    }

    /**
     * query thirdSystem by type.
     *
     * @param type type
     * @return ThirdSystemVo
     */
    public ResponseEntity<List<ThirdSystemVo>> getThirdSystemByType(String type) {
        List<ThirdSystem> ret = thirdSystemMapper.selectBySystemType(type);
        if (ret != null) {
            return ResponseEntity.ok(ret.stream().map(ThirdSystem::toVo).collect(Collectors.toList()));
        } else {
            throw new AppException(QUERY_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_QUERY_THIRD_SYSTEM_FAILED);
        }
    }

    /**
     * query thirdSystem by like name.
     *
     * @param name name
     * @return ThirdSystem
     */
    public ResponseEntity<List<ThirdSystemVo>> selectByNameLike(String name, String type) {
        List<ThirdSystem> ret = thirdSystemMapper.selectByNameLike(name, type);
        if (ret != null) {
            return ResponseEntity.ok(ret.stream().map(ThirdSystem::toVo).collect(Collectors.toList()));
        } else {
            throw new AppException(QUERY_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_QUERY_THIRD_SYSTEM_FAILED);
        }
    }

    /**
     * update a thirdSystem.
     *
     * @param id id
     * @param thirdSystem thirdSystem
     * @return String
     */
    public ResponseEntity<String> updateThirdSystem(String id, ThirdSystem thirdSystem) {
        ThirdSystem record = thirdSystemMapper.selectByPrimaryKey(id);
        if (record == null) {
            LOGGER.error(THIRD_SYSTEM_ERR_NOT_FOUND_MESSAGES);
            throw new AppException(THIRD_SYSTEM_ERR_NOT_FOUND_MESSAGES, ResponseConst.RET_THIRD_SYSTEM_NOT_FOUND);
        }

        thirdSystem.setId(id);
        // if password is not empty, need encrypt
        String password = thirdSystem.getPassword();
        if (password != null && !password.isEmpty()) {
            thirdSystem.setPassword(AesUtil.encode(clientId, password));
        }
        int ret = thirdSystemMapper.updateByPrimaryKeySelective(thirdSystem);
        if (ret > 0) {
            LOGGER.info(UPDATE_THIRD_SYSTEM_SUCCESS_MESSAGES);
            return ResponseEntity.ok(UPDATE_THIRD_SYSTEM_SUCCESS_MESSAGES);
        } else {
            LOGGER.error(UPDATE_THIRD_SYSTEM_ERR_MESSAGES);
            throw new AppException(UPDATE_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_UPDATE_THIRD_SYSTEM_FAILED);
        }
    }

    /**
     * delete a thirdSystem.
     *
     * @param id thirdSystem id
     * @return String
     */
    public ResponseEntity<String> deleteThirdSystem(String id) {
        int ret = thirdSystemMapper.deleteByPrimaryKey(id);

        if (ret < 0) {
            LOGGER.error(DELETE_THIRD_SYSTEM_ERR_MESSAGES);
            throw new AppException(DELETE_THIRD_SYSTEM_ERR_MESSAGES, ResponseConst.RET_DELETE_THIRD_SYSTEM_FAILED);
        } else {
            LOGGER.info(DELETE_THIRD_SYSTEM_SUCCESS_MESSAGES);
            return ResponseEntity.ok(DELETE_THIRD_SYSTEM_SUCCESS_MESSAGES);
        }
    }

}
